/* Name: Sound
 * Author: John Gideon
 * Date: 5-3-12
 * Description: Used for playing .wav files and .mp3 files for sound in the game
 * Revisions: See Subversion logs at http://code.google.com/p/software-engineering-2012/source/list
 */

import java.io.File;
import java.io.IOException;
import java.util.HashMap;

import javax.sound.sampled.*;
import java.io.BufferedInputStream;
import java.io.FileInputStream;

import javazoom.jl.player.Player;

public class Sound {
	final static String EFFECT_CLICK = "/sound/effects/click.wav";
	final static String EFFECT_START = "/sound/effects/start.wav";
	final static String EFFECT_CREATEWH = "/sound/effects/createWH.wav";
	final static String EFFECT_POWERDOWN = "/sound/effects/powerdown.wav";
	final static String EFFECT_DELETEWH = "/sound/effects/deleteWH.wav";
	final static String EFFECT_GRB = "/sound/effects/grb.wav";
	final static String EFFECT_SUPERNOVA = "/sound/effects/supernova.wav";
	final static String EFFECT_PROBE = "/sound/effects/probe.wav";
	final static String EFFECT_WIN = "/sound/effects/win.wav";
	final static String EFFECT_LOSE = "/sound/effects/lose.wav";
	final static String EFFECT_ALARM = "/sound/effects/alarm.wav";
	final static String EFFECT_FUELALARM = "/sound/effects/fuelAlarm.wav";
	
	final static String MUSIC_TITLE = "sound/music/title.mp3";
	final static String MUSIC_DARKSPACE = "sound/music/darkspace.mp3";
	
	private static HashMap<String,Clip> effects = new HashMap<String,Clip>();
	public static Player player; 
	private static Thread thread;
	private static String musicPath;
	public static Boolean isMuted = false;
	
	// Preloads all effects into a hashmap cache so that they play instantaneously when called
	public static void init(){
		loadEffect(EFFECT_CLICK);
		loadEffect(EFFECT_START);
		loadEffect(EFFECT_CREATEWH);
		loadEffect(EFFECT_POWERDOWN);
		loadEffect(EFFECT_DELETEWH);
		loadEffect(EFFECT_GRB);
		loadEffect(EFFECT_SUPERNOVA);
		loadEffect(EFFECT_PROBE);
		loadEffect(EFFECT_WIN);
		loadEffect(EFFECT_LOSE);
		loadEffect(EFFECT_ALARM);
		loadEffect(EFFECT_FUELALARM);
	}
	
	// Allows for the preloading of a single effect .wav file into the hashmap
	private static Clip loadEffect(String path) {
        try {
			// Open an audio input stream.
			File soundFile = new File(System.getProperty("user.dir")+path);
			AudioInputStream soundIn = AudioSystem.getAudioInputStream(soundFile);
			AudioFormat format = soundIn.getFormat();
			DataLine.Info info = new DataLine.Info(Clip.class, format);
			Clip clip = (Clip)AudioSystem.getLine(info);
			clip.open(soundIn);
	        effects.put(path, clip);
	        return clip;
	    } catch (UnsupportedAudioFileException e) {
		    e.printStackTrace();
		} catch (IOException e) {
		    e.printStackTrace();
		} catch (LineUnavailableException e) {
		    e.printStackTrace();
		}
        return null;
	}
	
	// Plays a sound effect from the cache and restarts it if already playing
	// http://www3.ntu.edu.sg/home/ehchua/programming/java/J8c_PlayingSound.html
	public static void effect(String path) {
		if (isMuted) {return;}
		if (effects.get(path) != null) {
			Clip playClip = (Clip) effects.get(path);
			playClip.setFramePosition(0);
		    playClip.start();
		}
	}
	
	// Loops an mp3 background music file
	//http://introcs.cs.princeton.edu/java/faq/mp3/MP3.java.html
	public static void playMusic(String path) {
		if (isMuted) {return;}
        try {
        	musicPath = path;
            FileInputStream fis     = new FileInputStream(path);
            BufferedInputStream bis = new BufferedInputStream(fis);
            player = new Player(bis);
            
        }
        catch (Exception e) {
        }

        // run in new thread to play in background
        thread = new Thread() {
            public void run() {
                try { Sound.player.play(); }
                catch (Exception e) { System.out.println(e); }
                while (true) {
                	if (Sound.player.isComplete()) {
                		Sound.player.close();
                		try {
						    FileInputStream fis     = new FileInputStream(Sound.musicPath);
						    BufferedInputStream bis = new BufferedInputStream(fis);
						    player = new Player(bis);
						}
						catch (Exception e) {
						}
						try { Sound.player.play(); }
						catch (Exception e) { System.out.println(e); }
                	}
                }
            }
        };
        thread.start();
	}
	
	// Stops a currently playing mp3
	public static void stopMusic() {
		Sound.player.close();
		thread.stop();
	}
	
	// Stops any current music and prevents any effects from being played
	public static void mute() {
		isMuted = true;
		stopEffect(Sound.EFFECT_FUELALARM);
		stopMusic();
	}
	
	// Allows effects to be played and restarts the background music depending on the room
	public static void unmute() {
		isMuted = false;
		switch (Game.currentRoom) {
			case Game.ROOM_START:
				playMusic(MUSIC_TITLE);
				break;
			case Game.ROOM_HELP:
				playMusic(MUSIC_TITLE);
				break;
			case Game.ROOM_GAME:
				playMusic(MUSIC_DARKSPACE);
				break;
		}
	}
	
	// Toggles the current mute state
	public static void toggleMute() {
		if (isMuted) {
			unmute();
		} else {
			mute();
		}
	}
	
	// Loops an effect (Used for FUELALARM)
	public static void loopEffect(String path) {
		if (isMuted) {return;}
		if (effects.get(path) != null) {
			Clip playClip = (Clip) effects.get(path);
			if (!playClip.isRunning()) {
				playClip.setFramePosition(0);
				playClip.start();
			}
		}
	}
	
	// Stops a looping effect (Used for FUELALARM)
	public static void stopEffect(String path) {
		if (effects.get(path) != null) {
			Clip playClip = (Clip) effects.get(path);
			playClip.stop();
			playClip.setFramePosition(0);
		}
	}
	
}

